﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using DiscoveryLogic.Analytics.BusinessLogic.Dedups;
using DiscoveryLogic.Analytics.BusinessLogic.Importers;
using DiscoveryLogic.Analytics.BusinessLogic.Links;
using DiscoveryLogic.Analytics.BusinessLogic.Rules;
using DiscoveryLogic.Analytics.BusinessLogic.Scenarios;
using DiscoveryLogic.Analytics.DataObjects;
using DiscoveryLogic.Analytics.DataObjects.Dedup;
using DiscoveryLogic.Analytics.DataObjects.Networks;
using DiscoveryLogic.Analytics.DataObjects.Rules;
using DiscoveryLogic.Common.Utilities;

namespace DiscoveryLogic.Analytics.Modules.Networks
{
    /// <summary>
    /// Interaction logic for SponsoringOrgsViaMeshTerms.xaml
    /// </summary>
    public partial class SponsoringOrgsViaMeshTerms : UserControl
    {
        public delegate void OnNetworkCreated(Network network);
        public event OnNetworkCreated NetworkCreated;

        public delegate void OnStatusChanged(string msg, int pct);
        public event OnStatusChanged StatusChanged;

        private class BgWorkerArg
        {
            public string NetworkName;
            public List<string> MeshTerms;
            public bool IsMajorTopic;
            public List<int> pubYears;
            public EntityRelationRule PubToGrantLinkRule;
            public EntityRelationRule GrantToOrgLinkRule;
            public EntityDedupRule OrgDedupRule;
        }

        private BackgroundWorker _BgWorker;
        private Dictionary<string, EntityDedupRule> _DedupRules;
        private Dictionary<string, EntityRelationRule> _LinkRules;
        private string _NetworkName;

        public SponsoringOrgsViaMeshTerms()
        {
            InitializeComponent();
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            this.cboDedupRules.Items.Clear();
            this._DedupRules = new Dictionary<string, EntityDedupRule>();
            List<RuleBase> rules = RuleManager.GetRulesByType(RuleType.Dedup, EntityIcons.DedupRuleIcon);
            if (rules != null && rules.Count > 0)
            {
                foreach (RuleBase rule in rules)
                {
                    if (rule.SrcEntityType == EntityType.Organizations)
                    {
                        this._DedupRules.Add(rule.RuleName, rule as EntityDedupRule);
                        this.cboDedupRules.Items.Add(rule.RuleName);
                    }
                }
                if (this.cboDedupRules.Items.Count > 0)
                    this.cboDedupRules.SelectedIndex = 0;
            }

            this.cboPubGrants.Items.Clear();
            this.cboGrantOrgs.Items.Clear();
            this._LinkRules = new Dictionary<string, EntityRelationRule>();
            rules = RuleManager.GetRulesByType(RuleType.Link, EntityIcons.LinkRuleIcon);
            if (rules != null && rules.Count > 0)
            {
                foreach (RuleBase rule in rules)
                {
                    if (rule.SrcEntityType == EntityType.Publications &&
                        rule.TgtEntityType == EntityType.Grants)
                    {
                        this.cboPubGrants.Items.Add(rule.RuleName);
                    }
                    else if (rule.SrcEntityType == EntityType.Grants &&
                        rule.TgtEntityType == EntityType.Organizations)
                    {
                        this.cboGrantOrgs.Items.Add(rule.RuleName);
                    }
                    this._LinkRules.Add(rule.RuleName, rule as EntityRelationRule);
                }
                if (this.cboPubGrants.Items.Count > 0)
                    this.cboPubGrants.SelectedIndex = 0;
                if (this.cboGrantOrgs.Items.Count > 0)
                    this.cboGrantOrgs.SelectedIndex = 0;
            }

            this.cboFromPubYear.Items.Clear();
            this.cboToPubYear.Items.Clear();
            for(int i=1980; i<=DateTime.Now.Year; i++)
            {
                this.cboFromPubYear.Items.Add(i.ToString());
                this.cboToPubYear.Items.Add(i.ToString());
            }
        }

        private void btnOK_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (this.cboPubGrants.SelectedIndex < 0)
                {
                    MessageBox.Show("Define pub-grant link rule first");
                    return;
                }
                if (this.cboGrantOrgs.SelectedIndex < 0)
                {
                    MessageBox.Show("Define grant-org link rule");
                    return;
                }

                if (this.cboDedupRules.SelectedIndex < 0)
                {
                    MessageBox.Show("Define org dedup rule first");
                    return;
                }
                if (string.IsNullOrEmpty(this.txtNetworkName.Text))
                {
                    MessageBox.Show("Enter a name for network");
                    return;
                }
                if (string.IsNullOrEmpty(this.txtMeshTerms.Text))
                {
                    MessageBox.Show("Enter project ID or grant number");
                    return;
                }

                this._NetworkName = this.txtNetworkName.Text;
                BgWorkerArg arg = new BgWorkerArg();
                arg.MeshTerms=new List<string>();
                string[] meshTerms = this.txtMeshTerms.Text.Split(new char[] { '\n', '\r' });
                foreach (string meshTerm in meshTerms)
                {
                    if (meshTerm.Trim().Length > 0)
                    {
                        if (!arg.MeshTerms.Contains(meshTerm.Trim()))
                            arg.MeshTerms.Add(meshTerm.Trim());
                    }
                }
                arg.NetworkName = this.txtNetworkName.Text;
                arg.PubToGrantLinkRule = this._LinkRules[this.cboPubGrants.SelectedItem.ToString()];
                arg.GrantToOrgLinkRule = this._LinkRules[this.cboGrantOrgs.SelectedItem.ToString()];
                arg.OrgDedupRule = this._DedupRules[this.cboDedupRules.SelectedItem.ToString()];
                arg.IsMajorTopic = this.ckMajorTopic.IsChecked.Value;
                arg.pubYears=new List<int>();
                if(this.cboFromPubYear.SelectedIndex>=0 && this.cboToPubYear.SelectedIndex>=0)
                {
                    int fromYr = int.Parse(this.cboFromPubYear.SelectedItem.ToString());
                    int toYr = int.Parse(this.cboToPubYear.SelectedItem.ToString());
                    if(fromYr <= toYr)
                    {
                        for(int i=fromYr; i<=toYr;i++)
                        {
                            arg.pubYears.Add(i);
                        }
                    }
                }

                this._BgWorker = new BackgroundWorker();
                this._BgWorker.WorkerReportsProgress = true;
                this._BgWorker.WorkerSupportsCancellation = true;
                this._BgWorker.ProgressChanged += new ProgressChangedEventHandler(_BgWorker_ProgressChanged);
                this._BgWorker.DoWork += new DoWorkEventHandler(_BgWorker_DoWork);
                this._BgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_BgWorker_RunWorkerCompleted);

                this._BgWorker.RunWorkerAsync(arg);

                if (this.Parent is Window)
                {
                    ((Window)this.Parent).Close();
                }
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.Message);
            }
        }

        void _BgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (!string.IsNullOrEmpty(this._NetworkName))
            {
                try
                {
                    Network network = Network.Read(this._NetworkName);
                    if (network != null && this.NetworkCreated != null)
                    {
                        this.NetworkCreated(network);
                    }
                }
                catch (Exception ex)
                {
                    System.Windows.Forms.MessageBox.Show(ex.Message);
                }
            }
        }

        void _BgWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                this._BgWorker.ReportProgress(10, "Creating sponsor network...");

                BgWorkerArg arg = (BgWorkerArg)e.Argument;

                /*
                List<PublicationDO> pubs = PubImportUtil.GetPublicationsByMeshTerms(arg.MeshTerms);
                if (pubs == null)
                {
                    throw new Exception("Unable to get pubs");
                }
                else
                {
                    // grant -> pubs 
                    this._BgWorker.ReportProgress(10, "Reading grants into network...");
                    Network network = new Network(arg.NetworkName, new List<EntityBase>(), new List<Link>());
                    List<string> keys1 = new List<string>();
                    foreach (PublicationDO pub in pubs)
                    {
                        network.Records.Add(pub);
                        keys1.Add(pub.PKValue());
                    }
                    // pubs -> grants 
                    this._BgWorker.ReportProgress(20, "Linking publications to grants...");
                    EntityRelationWorker linkWorker1 = new EntityRelationWorker(arg.PubToGrantLinkRule, network, keys1);
                    network = linkWorker1.ReadRelatedData();
                    // grants -> orgs 
                    this._BgWorker.ReportProgress(40, "Linking grants to orgs...");
                    List<string> keys3 = new List<string>();
                    foreach (EntityBase entity in network.Records)
                    {
                        if (entity.EntityType == EntityType.Grants)
                            keys3.Add(entity.PKValue());
                    }
                    EntityRelationWorker linkWorker3 = new EntityRelationWorker(
                        arg.GrantToOrgLinkRule, network, keys3);
                    network = linkWorker3.ReadRelatedData();
                    // org -> dedup 
                    this._BgWorker.ReportProgress(50, "Dedup orgs...");
                    NetworkDedupSetting dedupSetting = new NetworkDedupSetting();
                    dedupSetting.DedupRules = new Dictionary<EntityType, string>();
                    dedupSetting.DedupRules.Add(EntityType.Organizations, arg.OrgDedupRule.RuleName);
                    dedupSetting.NetworkName = arg.NetworkName;
                    NetworkDedupWorker dedupWorker = new NetworkDedupWorker(network, dedupSetting);
                    network = dedupWorker.DedupNetwork();
                    this._BgWorker.ReportProgress(85, "Hide linkages via pubs...");
                    Graph graph = new Graph(network);
                    List<EntityType> aggregateOnTypes = new List<EntityType>();
                    aggregateOnTypes.Add(EntityType.Publications);
                    graph.RemoveAllEntityTypesExcept(
                        EntityType.Organizations, 4,
                        aggregateOnTypes, null);

                    this._BgWorker.ReportProgress(95, "Saving network...");
                    List<Link> links = new List<Link>();
                    foreach (Edge edge in graph.Edges.Values)
                    {
                        Link link = edge.Tag;
                        links.Add(link);
                    }
                    List<EntityBase> entities = new List<EntityBase>();
                    foreach (Vertice v in graph.Vertices.Values)
                    {
                        if (v.Tag.EntityType != EntityType.Grants)
                            entities.Add(v.Tag);
                    }
                    network.Records = entities;
                    network.Links = links;

                    network.Save();
                }
                */

                Network network = OrgNetworkBuilder.BuildNetworkViaMeshTerms(
                    arg.NetworkName, arg.MeshTerms, arg.IsMajorTopic, arg.pubYears);
                network.Save();
                this._BgWorker.ReportProgress(0, "Sponsoring network created.");
            }
            catch (Exception ex)
            {
                ExceptionHandler.HandlesException(ex);
                this._BgWorker.ReportProgress(0, ex.Message);
            }
        }

        void _BgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if (this.StatusChanged != null)
            {
                this.StatusChanged(e.UserState.ToString(), e.ProgressPercentage);
            }
        }

        private void btnCancel_Click(object sender, RoutedEventArgs e)
        {
            if (this.Parent is Window)
            {
                ((Window)this.Parent).Close();
            }
        }
    }
}
